%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: Peter
%% Progress to usefulness: 
%%
%% Implementation of 'Block Store', as suggested
%% in Figure 1 in the chord paper.
%% 
%% UPDATE: This process is only used by calls from 
%% the node process. Each socket connection is assigned
%% a store worker, which all calls to the database
%% should go through.
%%
%% Handles storing of values at the responsible node
%%
%% External function calls:
%% 
%% {put, Key, Value} -- Store 'Key' and 'Value' at correct node
%% {get, Key}        -- Get value from node holding 'Key'
%%
%%%%%%%%%%%%%%%%%%%%%%%

-module(store).
-behaviour(gen_server).
-include("db.hrl").

% gen_server API
-export([start_link/0]).

% gen_server API
-export([init/1, handle_call/3,handle_cast/2,handle_info/2
        ,terminate/2, code_change/3]).


start_link() ->
    io:format("Starting Store master worker\n"),
    gen_server:start_link({local, ?STORAGE},?MODULE,#store{},[]).

% Initial dictionary
% should return {ok, State}
init(State) ->
    {ok, State}.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   Internal "function calls"
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% Handle put
%
%
handle_call({put, Key, Value}, _From, State) ->
    Dest  = gen_server:call(?NETWORK,{lookup, Key}),
    Reply = gen_server:call({?BACKEND,Dest}, {put, Key, Value}),
    visual:visual_element(Key,Value,Dest,[]),
    {reply,Reply, State};
%
% Handle get
%
handle_call({get, Key}, _From, State) ->
    Dest  = gen_server:call(?NETWORK,{lookup, Key}),
    Reply = gen_server:call({?BACKEND,Dest}, {get, Key}),
    {reply, Reply, State};

%
% This node wants to join a network, knows about 'Node'
%
handle_call({join, Node}, _From, State) ->
    Connected = State#store.connected,
    case Connected of
        true  -> 
            {reply, {error, already_connected}, State};
        false ->
            {ok,Succ} = gen_server:call(?NETWORK, {join, Node}),
            visual:visual_node(node(),[]),
            gen_server:call({?BACKEND,Succ}, {join}),
            {reply,{ok, join},State#store{connected=true}}
    end;

handle_call({start_ring}, _From, State) ->
    {ok} = gen_server:call(?NETWORK, {start_ring}),
    visual:visual_node(node(),[]),
    {reply, {ok}, State#store{connected = true}};

%
% This node want to leave chord network, send values to the new responsible node.
%
handle_call({leave}, _From, State) ->
    Connected = State#store.connected,
    case Connected of
        true ->
            % Tell dht to leave network, returns the new responsible node
            case gen_server:call(?NETWORK, {leave}) of
                last_node -> ok;
                Node -> % Tell backend to send its values to the new node
                        gen_server:call(?BACKEND, {leave,Node})
            end;
        false -> ok
    end,
    {reply, ok, State#store{connected=false}};

%
% Status, returns the current state (values)
%
handle_call({status}, _From, State) ->
    Nodes = gen_server:call(?NETWORK,{status}),
    Values = gen_server:call(?BACKEND,{status}),
    {reply, {Nodes,Values}, State}.



handle_cast(_Msg, State) ->
    {noreply, State}.

terminate(_Reason,_State) ->
    io:format("Terminating Block Store~n").


handle_info(Info, _State) ->
    io:format("Info message received: ~w~n",[Info]).

code_change(_OldVsn, _State, _Extra) ->
    undefined.
